home *** CD-ROM | disk | FTP | other *** search
- /*
- * Draft mode, text-only printing code for the Macintosh.
- */
- /*
- * This file is part of the DMP-110 printer driver for the Macintosh
- * series of computers.
- */
- /*
- * Earle R. Horton.
- * Wednesday, November 30, 1988
- * All rights reserved.
- */
- #include <Windows.h>
- #include <Events.h>
- #include <Dialogs.h>
- #include <Fonts.h>
- #include <Memory.h>
- #include <Resources.h>
- #include <ToolUtils.h>
- #include <Errors.h>
- #include <OSUtils.h>
- #include <Desk.h>
- #include "dmp-110.h"
- #include "compat.h"
-
- #define __SEG__ Main
-
- /*
- * Use our own names for these.
- */
- #define storage lGParam1
- #define pagenum lGParam2
- #define PREC lGParam3
- #define picture lGParam4
-
- /* Useful constants */
- #define SERRESET 8
- #define SERSHAKE 10
-
- #define XONCR ((char)17)
- #define XOFFCR ((char)19)
- #define RESFILEID (-8192)
-
- OSErr SPOpen();
-
- #define WNETrapNumber 0x60
- #define UnImpTrapNumber 0x9f
- /*
- * Abort printing if command '.' pressed.
- */
- checkabort()
- {
- EventRecord myevent;
- Boolean result;
- Boolean WNEisThere = NGetTrapAddress(WNETrapNumber,1) !=
- NGetTrapAddress(UnImpTrapNumber,1);
-
- if(WNEisThere){
- result = WaitNextEvent(everyEvent,&myevent,0L,0L);
- }else{
- SystemTask();
- result = GetNextEvent(keyDownMask|autoKeyMask, &myevent);
- }
- if(result){
- if(LoWord(myevent.message & charCodeMask) == '.' &&
- (myevent.modifiers & cmdKey) ){
- PrSetError(iIOAbortErr); /* iPrAbort? */
- }
- }
- }
- /*
- * This function returns a pointer to a specialized GrafPort
- * (a TPrPort) customized for printing.
- *
- * Based on the passed Print Record, we prepare a GrafPort for use
- * by the application in printing. We store information of use to
- * us in the lGParam[n] fields of the TPrPort. We use a BitMap
- * whose baseAddr contains a pointer to a buffer whose size is
- * taken from the prXInfo field of the print record. We define the
- * portRect to correspond to the prInfo.rPage field of the print
- * record. Later, we will scale the application's drawing commands
- * to fit into the prInfoPT.rPage Rect, and print the Picture which
- * the application has created.
- */
-
- pascal TPPrPort myPrOpenDoc(hPrint,pPrPort,pIOBuf)
- THPrint hPrint;
- TPPrPort pPrPort;
- Ptr pIOBuf;
- {
- TPPrPort thisport;
- Handle us;
- THPrint savePrint;
- BitMap mybits;
- THPrint ourPrint;
- DCtlHandle d;
- DPstorage s;
- SysEnvRec World;
- short refnum;
- /*
- * Allocate storage, abort if no space for TPrPort.
- * First stage aborts if not enough for a TPrPort, setting
- * PrError() to memFullErr and returning nil.
- */
- if(pPrPort == nil){
- if((thisport = (TPPrPort)
- NewPtr((Size)sizeof(TPrPort))) == nil){
- PurgeMem(maxSize);
- thisport = (TPPrPort)NewPtr((Size)sizeof(TPrPort));
- if(thisport == nil){
- PrSetError(memFullErr);
- return nil;
- }
- }
- thisport->fOurPtr = TRUE; /* TRUE: Belongs to printing code. */
- }
- else {
- thisport = pPrPort;
- thisport->fOurPtr = FALSE; /* FALSE: Belongs to application. */
- }
- thisport->fOurBits = TRUE;
- /*
- * If we get here, there is enough space for at least the TPrPort.
- *
- * The next block of code attempts to allocate all the dynamic storage
- * we will need during printing. If it fails, it sets thisport->storage
- * to nil, and sets PrError() to memFullErr. The application should detect
- * the print error condition, and call PrCloseDoc. Dynamic storage which
- * was not allocated successfully is disposed of by PrCloseDoc. Storage
- * is allocated in several blocks rather than in a single big block in
- * order to facilitate changing the size of the output buffer or band.
- */
- thisport->storage = (long)(s = (DPstorage)NewPtr((Size)sizeof(Dstorage)));
- if(s != nil){
- memset(s,0,sizeof(Dstorage));
- s->obuf = NewPtr((Size)2000);
- }
- ourPrint = hPrint;
- if(HandToHand(&ourPrint) == noErr){
- thisport->PREC = (long)ourPrint;
- }else{
- thisport->PREC = nil;
- }
- thisport->gPort.portBits.baseAddr = mybits.baseAddr = NewPtr((Size)
- ((*hPrint)->prXInfo.iRowBytes*(*hPrint)->prXInfo.iBandV));
- if( (thisport->storage == nil) ||
- (s->obuf == nil) ||
- (thisport->PREC == nil) ||
- (mybits.baseAddr == nil) ){
- PrSetError(memFullErr);
- }else{
-
- /*
- * If we get here, then memory worries are over, except of course if we
- * run out while defining a picture. Don't know what happens then.
- * The TPrPort is ready to be initialized, and the serial port to be
- * opened. Only possible fatal error remaining is a serial port error.
- */
-
- OpenPort(thisport);
-
- SetStdProcs(&thisport->gProcs); /* Fill out gProcs for this port. */
- thisport->gPort.grafProcs = &thisport->gProcs;
- SetPort(thisport);
-
- SysEnvirons(1,&World);
- PrSetError(SPOpen(s,&World));
-
- /*
- * Save our copy of Print Record Handle, then open the port.
- */
- thisport->PREC = (long)ourPrint;
-
- /*
- * Define the port's BitMap as our printing band.
- *
- */
- mybits.bounds.top = 0;
- mybits.bounds.left = 0;
- mybits.bounds.bottom = (*hPrint)->prXInfo.iBandV;
- mybits.bounds.right = (*hPrint)->prXInfo.iBandH+1;
- mybits.rowBytes = (*hPrint)->prXInfo.iRowBytes;
-
- SetPortBits(&mybits);
-
- MovePortTo((*hPrint)->prInfo.rPage.left,(*hPrint)->prInfo.rPage.top);
-
- PortSize((*hPrint)->prInfo.rPage.right-(*hPrint)->prInfo.rPage.left,
- (*hPrint)->prInfo.rPage.bottom-(*hPrint)->prInfo.rPage.top);
-
- RectRgn(thisport->gPort.visRgn,&thisport->gPort.portRect);
- RectRgn(thisport->gPort.clipRgn,&thisport->gPort.portRect);
-
- thisport->pagenum = 1;
- thisport->storage = (long)s;
- if((*ourPrint)->prJob.pIdleProc == nil)
- (*ourPrint)->prJob.pIdleProc = (ProcPtr)checkabort;
- /*
- * Attempt to save Print Record in 'PREC' 1 in the printer file.
- * No big deal if failure, since this is not essential to printing.
- */
- savePrint = (THPrint)GetResource('PREC',1);
- if(savePrint != nil){
- LoadResource(savePrint);
- **savePrint = **ourPrint;
- ChangedResource(savePrint);
- UpdateResFile(HomeResFile(savePrint));
- }
- }
- return thisport;
- }
- /*
- * Called at completion of a print job, whether successful or not.
- * Clean up any dynamic storage which requires it, then set print
- * error to noErr.
- */
- pascal void myPrCloseDoc(pPrPort)
- TPPrPort pPrPort;
- {
- DPstorage s;
- if( (pPrPort != nil) &&
- ((s = (DPstorage)pPrPort->storage) != nil) &&
- (s->obuf != nil) &&
- (pPrPort->PREC != nil) &&
- (pPrPort->gPort.portBits.baseAddr != nil) ) { /* Assume successful open. */
- ClosePort(pPrPort);
- PBClose(&s->iopb,FALSE);
- }
- if(pPrPort != nil){ /* Dispose of storage which needs it. */
- if(s != nil){
- if(s->obuf != nil){
- DisposPtr(s->obuf);
- }
- DisposPtr(s);
- }
- if(pPrPort->PREC != nil){
- DisposHandle(pPrPort->PREC);
- }
- if(pPrPort->gPort.portBits.baseAddr != nil){
- DisposPtr(pPrPort->gPort.portBits.baseAddr);
- }
- if(pPrPort->fOurPtr){
- DisposPtr(pPrPort);
- }
- }
- PrSetError(noErr); /* No bad feelings! */
- }
- /*
- * This routine opens a new page. Check for valid TPrPort, then
- * just start a new picture definition.
- */
- pascal void myPrOpenPage(pPrPort,pPageFrame)
- TPPrPort pPrPort;
- TPRect pPageFrame;
- {
- Rect *scalerect;
-
- if(pPageFrame != nil){
- scalerect = pPageFrame;
- }else{
- scalerect = &pPrPort->gPort.portRect;
- }
- SetPort(pPrPort);
- /*
- * The application may run out of memory while the picture is being
- * saved. Don't know how to prevent or even detect this from here.
- */
- pPrPort->picture = (long)OpenPicture(scalerect);
- }
- /*
- * This is the routine which does the actual printing.
- * Close the picture for the page. Use DrawPicture() to draw repeatedly,
- * while moving the BitMap down the page to capture an image for each
- * band.
- *
- * Send each band to the output conversion routines.
- */
- pascal void myPrClosePage(pPrPort)
- TPPrPort pPrPort;
- {
- PicHandle thepic;
- short i,iocount,vband,nbands,rows,nleft;
- Rect savepr,scaleRect,savebm;
- long width,height;
- THPrint ourPrint;
- char formfeed;
- DPstorage s;
-
- ourPrint = (THPrint)pPrPort->PREC; /* Set up variables. */
- SetPort(pPrPort);
- ClosePicture();
- thepic = (PicHandle)pPrPort->picture;
- vband = (*ourPrint)->prXInfo.iBandV;
- nbands = (*ourPrint)->prXInfo.iBands;
- s = (DPstorage)pPrPort->storage;
- if(PrError() != noErr){
- }
- else if(setjmp(s->abortbuf) != 0){ /* Pops back here on abort or error. */
- PrSetError(iIOAbortErr);
- }
- else if(pPrPort->pagenum < (*ourPrint)->prJob.iFstPage){/* Check page no. */
- pPrPort->pagenum++;
- }
- else if(pPrPort->pagenum++ > (*ourPrint)->prJob.iLstPage){
- PrSetError(iIOAbortErr);
- } else {
- savepr = pPrPort->gPort.portRect;
- savebm = pPrPort->gPort.portBits.bounds;
-
- /*
- * Enlarge portRect of Printing Port.
- */
- OffsetRect(&pPrPort->gPort.portBits.bounds,-savebm.left,-savebm.top);
- scaleRect = (*ourPrint)->prInfoPT.rPage;
- OffsetRect(&scaleRect,-scaleRect.left,-scaleRect.top);
- pPrPort->gPort.portRect = scaleRect;
- RectRgn(pPrPort->gPort.visRgn,&scaleRect);
- RectRgn(pPrPort->gPort.clipRgn,&scaleRect);
-
- rows = scaleRect.bottom - scaleRect.top;
- if((*ourPrint)->prStl.feed != feedCut || waitnextpage()){
- for(i=0;i<rows;i+=vband){ /* Loop over all bands. */
- MovePortTo(scaleRect.left,-i); /* Move to next. */
- EraseRect(&scaleRect);
- DrawPicture(thepic,&scaleRect); /* Draw in the band. */
- dumpbits(pPrPort); /* Print it. */
- }
- formfeed = 12; /* Do a form feed. Device Dependent. */
- s->iopb.ioParam.ioReqCount = 1;
- s->iopb.ioParam.ioBuffer = &formfeed;
- asyncwrite(s,(*((THPrint)pPrPort->PREC))->prJob.pIdleProc);
- /*
- * Restore portRect so Application can draw in it.
- */
- pPrPort->gPort.portBits.bounds = savebm;
- pPrPort->gPort.portRect = savepr;
- RectRgn(pPrPort->gPort.visRgn,&savepr);
- RectRgn(pPrPort->gPort.clipRgn,&savepr);
-
- }else{
- PrSetError(iIOAbortErr); /* iPrAbort? */
- }
- }
- KillPicture(thepic);
- }
- dumpbits(pPrPort) /* Dump a printing band to the serial port. */
- TPPrPort pPrPort;
- {
- DPstorage s;
- int i,rows;
- BitMap *bits;
- ProcPtr idle;
- s = (DPstorage)pPrPort->storage;
- bits = &pPrPort->gPort.portBits;
- rows = bits->bounds.bottom-bits->bounds.top;
- idle = (*((THPrint)pPrPort->PREC))->prJob.pIdleProc;
- for (i=0;i<rows;i+=16){
- bitmap_to_hires(s,bits,i,rows-i,idle);
- if(PrError() != noErr)return;
- }
- }
- /*
- * bitmap_to_hires()
- * This function translates a QuickDraw BitMap to codes which may
- * be sent to a Tandy DMP-110 dot-matrix printer in high-resolution
- * graphics mode. Graphics codes for this printer in hi-res mode
- * include all eight bit characters. There are two characters for each
- * column of 16 dots on the paper. The top dot (1) corresponds to bit
- * zero of the first byte sent. The bottom dot (16) corresponds to bit
- * eight of the second byte. There are 960 columns, or 1920 bytes, of
- * graphics data to be sent for one line of graphics output.
- * Note that the ToolBox bit manipulation routines use lower-to-upper
- * bit order.
- *
- * No smarts in this routine, the whole 1918 bytes are sent for each
- * line.
- */
-
- bitmap_to_hires(s,b,row,nleft,idle)
- DPstorage s;
- BitMap *b; /* BitMap to print. */
- int row; /* Starting row on this pass. */
- int nleft; /* Max number of rows to print. */
- ProcPtr idle;
- {
- short *obytes,*inbytes;
- int column,lastcol,nbits,dot;
-
- obytes = (short *)s->obuf;
- for(dot=960;dot-- >0;){
- obytes[dot] = 0;
- }
- lastcol = b->bounds.right - b->bounds.left;
- lastcol = (lastcol > 959) ? 959 : lastcol;
- inbytes = (short *)(b->baseAddr + b->rowBytes*row);
- nbits = b->rowBytes*8;
- for(column=0;column<lastcol;column++){
- (*idle)();
- if(PrError() != noErr)return;
- for(dot=0;dot<8 && dot<nleft;dot++){
- if(BitTst(inbytes,(long)(column+dot*nbits))){
- BitSet(obytes,(long)(7-dot));
- }
- }
- for(dot=8;dot<16 && dot < nleft;dot++){
- if(BitTst(inbytes,(long)(column+dot*nbits))){
- BitSet(obytes,(long)(23-dot));
- }
- }
- obytes++;
- }
- output_hires_data(s,(long)(lastcol),idle); /* Send to printer. */
- }
- /*
- * output_hires_data() - Send a stream of high resolution graphics data
- * to the Tandy DMP-110. The codes for transferring the graphics, and
- * for the high-resolution paper advance, are hard-coded into this
- * routine. Skips blank graphics codes, and repositions the printer
- * head. The overhead is 8 bytes for repositioning the head and restarting
- * high resolution graphics. If there are four blank columns, then, we
- * break even. If there are more, we win. If there are less than four
- * blank columns, we lose.
- */
- output_hires_data(s,columns,idle)
- DPstorage s;
- long columns;
- ProcPtr idle;
- {
- unsigned char codes[10];
-
- short *p;
- short pos,ncodes,start;
- short *buf = (short *)s->obuf;
-
-
- for(pos=0,ncodes=0,p=buf,start=0;pos<960;pos++){
- if(buf[pos] == 0){
- if(ncodes != 0){
- sendcodes(s,p,ncodes,start,idle);
- if(PrError() != noErr)return;
- ncodes = 0;
- }
- }else{
- if(ncodes == 0){
- p = &buf[pos];
- start = pos;
- }
- ncodes++;
- }
- }
- if(ncodes != 0){
- sendcodes(s,p,ncodes,start,idle);
- }
- codes[0] = 26; /* DMP-110 carriage return. */
- codes[1] = 27; /* High res line feed. */
- codes[2] = 'G';
- s->iopb.ioParam.ioReqCount = 3L;
- s->iopb.ioParam.ioBuffer = (Ptr)codes;
- asyncwrite(s,idle);
- }
- sendcodes(s,buf,n,pos,idle)
- DPstorage s;
- char *buf;
- int n,pos;
- ProcPtr idle;
- {
- unsigned char codes[10];
- codes[0] = 27;
- codes[1] = 16;
- codes[2] = (pos>>8)&3;
- codes[3] = pos & 0xFF;
- codes[4] = 27;
- codes[5] = 73;
- codes[6] = (n>>8)&3;
- codes[7] = n&0xFF;
- s->iopb.ioParam.ioReqCount = 8L;
- s->iopb.ioParam.ioBuffer = (Ptr)codes;
- asyncwrite(s,idle);
- s->iopb.ioParam.ioReqCount = (long)(2*n);
- s->iopb.ioParam.ioBuffer = buf;
- asyncwrite(s,idle);
- }
- /*
- * Modal dialog box: "Insert next sheet."
- */
- waitnextpage()
- {
- DialogPtr sheetdialog;
- WindowPtr tempport;
- short itemhit,donetype;
- Handle doneitem;
- Rect donebox;
- if((sheetdialog = GetNewDialog(SHEETDIALOG, 0L,(WindowPtr) -1)) == nil)
- return FALSE;
- InitCursor();
- GetDItem(sheetdialog,DONEITEM,&donetype,&doneitem,&donebox);
- GetPort(&tempport);
- SetPort(sheetdialog);
- PenSize(3,3);
- InsetRect(&donebox,-4,-4);
- FrameRoundRect(&donebox,16,16);
- ModalDialog(0L,&itemhit);
- DisposDialog(sheetdialog);
- SetPort(tempport);
- if(itemhit == STOPITEM) return FALSE;
- return TRUE;
- }
- /*
- * Open the serial driver and configure it. Quit if ioResult field
- * of parameter block ever becomes other than noErr.
- */
- OSErr SPOpen(s,World)
-
- register DPstorage s;
- SysEnvRec *World;
- {
- register ParmBlkPtr pb;
- int serconfig;
- Pfg settings;
- OSErr error;
- extern char AOutName[],BOutName[];
- extern short BaudRates[];
- error = noErr;
- settings = (Pfg)(GetResource('HEXA',RESFILEID));
- if(settings == nil){ /* Where's our stuff? */
- return ResError();
- }
- LoadResource(settings);
- HNoPurge(settings);
- pb = &s->iopb;
- switch (pport){ /* get the correct port */
- case 0: /* modem port */
- pb->ioParam.ioNamePtr = (StringPtr)AOutName;
- break;
- case 1: /* printer port */
- if(IsMPPOpen()){
- (void)StopAlert(ATALKALERT,nil);
- return portInUse;
- }
- pb->ioParam.ioNamePtr = (StringPtr)BOutName;
- break;
- }
- PBOpen(pb,FALSE);
- if (pb->ioParam.ioResult != noErr){
- return(pb->ioParam.ioResult);
- }
- pb->ioParam.ioNamePtr = nil;
- /*
- * Set up the io parameter block for writing to the serial driver.
- * a control call resets the baud rate.
- * Another sets flow control.
- */
- ((CntrlParam *)pb)->csCode = SERRESET;
- serconfig = data8 + noParity + stop20;
- serconfig += BaudRates[pbaud];
- ((CntrlParam*)pb)->csParam[0] = serconfig;
- PBControl(pb,FALSE);
- if (pb->ioParam.ioResult != noErr) return(pb->ioParam.ioResult);
- #define shake ((SerShk *)&((CntrlParam*)pb)->csParam[0])
- shake->errs = FALSE;
- shake->evts = FALSE;
- shake->fDTR = FALSE;
- shake->fInX = FALSE;
- if(XonXoff && (World->machineType >= envMachUnknown)){
- shake->fXOn = TRUE;
- shake->fCTS = FALSE;
- shake->xOn = XONCR;
- shake->xOff = XOFFCR;
- }
- else {
- shake->fXOn = FALSE;
- shake->fCTS = TRUE;
- }
- ((CntrlParam *)pb)->csCode = SERSHAKE;
- PBControl(pb,FALSE);
- if (pb->ioParam.ioResult != noErr) return(pb->ioParam.ioResult);
-
- pb->ioParam.ioPosMode = 0;
- pb->ioParam.ioPosOffset = 0;
- ReleaseResource(settings);
- return(noErr);
- }
-
- /*
- * Routine to write asynchronously to the serial port, and run an
- * idle procedure while we wait. The idle routine may call PrSetError(),
- * so we check PrError() for abort each time. Kill pending serial port
- * IO if abort detected.
- */
- asyncwrite(s,idle)
- DPstorage s;
- ProcPtr idle;
- {
- IOParam *p = &(s->iopb.ioParam);
- PBWrite(p,TRUE); /* Issue ASYNC write. */
- do{
- (*idle)(); /* Idle til done. */
- if(PrError() != noErr){ /* Check for abort. */
- if(p->ioResult > 0){ /* More chars? */
- PBKillIO(p,FALSE); /* Stop output. */
- }
- longjmp(s->abortbuf,1); /* Get out. */
- }
- }while(p->ioResult > 0); /* Check for complete. */
- if(p->ioResult < 0){ /* Serial port Error! */
- longjmp(s->abortbuf,1);
- }
- }
-
-
-